package com.system.manager.modules.authorized.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.system.manager.common.constant.SysConstants;
import com.system.manager.common.entity.PageDTO;
import com.system.manager.common.entity.Result;
import com.system.manager.common.entity.TokenResult;
import com.system.manager.common.entity.UserExclTemplate;
import com.system.manager.common.enums.fileType.ExclFile;
import com.system.manager.common.exception.SysException;
import com.system.manager.modules.authorized.entity.AuthenticationResultDTO;
import com.system.manager.modules.authorized.entity.User;
import com.system.manager.modules.authorized.entity.UserExcel;
import com.system.manager.modules.authorized.enums.AuthorizationErrorCode;
import com.system.manager.modules.authorized.exception.AuthorizationException;
import com.system.manager.modules.authorized.mapper.UserMapper;
import com.system.manager.modules.authorized.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.system.manager.modules.authorized.vo.LoginUser;
import com.system.manager.utils.MD5Utils;
import com.system.manager.utils.TokenManager;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yxp
 * @since 2021-10-18
 */
@Transactional
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private TokenManager tokenManager;

    /**
     * 用户登陆
     *
     * @param loginUser
     * @return
     */
    @Override
    public AuthenticationResultDTO login(LoginUser loginUser) {

        // 1.判断证号是否存在
        User user = selectByAccount(loginUser.getUsername());

        if (user == null) {
            // 1.1 用户为null，表示不存在，返回错误信息
            throw new AuthorizationException(AuthorizationErrorCode.USER_NOT_EXISTS);
        }

        // 2.判断用户密码是否正确
        // 2.2 进行判断
        if (!user.getDeCodePswd().equals(loginUser.getPassword())) {
            throw new AuthorizationException(AuthorizationErrorCode.USER_NOT_EXISTS);
        }

        // 3.用户存在，生成token类
        AuthenticationResultDTO resultDTO = makeAuthenticationResult(user.getUserId(), user.getRole());

        return resultDTO;
    }

    /**
     * 根据用户的帐号查找对应的信息
     *
     * @param userAccount
     * @return
     */
    public User selectByAccount(String userAccount) {
        return userMapper.selectByAccount(userAccount);
    }

    /**
     * 根据分页查询出所有的用户
     *
     * @param currPage
     * @param size
     * @return
     */
    @Override
    public PageDTO<User> selectUsers(Integer currPage, Integer size) {
        IPage<User> userPage = new Page<>(currPage, size);
        // 1.查询出当前所有的对象，并进行分页封装
        page(userPage, new QueryWrapper<User>());

        // 2.将查询出来的数据返回给前端
        PageDTO<User> userPageDTO = new PageDTO<>();
        userPageDTO.setData(userPage.getRecords());
        userPageDTO.setCount(userPage.getTotal());

        return userPageDTO;
    }

    @Override
    public PageDTO<User> selectUsersCondition(Integer currPage, Integer size, Integer role, String userAccount, String name, String phone) {

        Page<User> userPage = new Page<>(currPage, size);
        // 1.根据条件查询出当前所有的对象，并进行分页封装
        List<User> userList = new ArrayList<>();
        try {
            userList = userMapper.selectUsersCondition(userPage, role, userAccount, name, phone);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException();
        }

        // 2.将查询出来的数据返回给前端
        PageDTO<User> userPageDTO = new PageDTO<>();
        userPageDTO.setData(userList);
        userPageDTO.setCount(userPage.getTotal());
        return userPageDTO;
    }

    /**
     * 插入新的用户
     *
     * @param user
     * @return
     */
    @Override
    public User insert(User user) {

        // 1.先判断证号是否已经存在
        User selectByAccount = selectByAccount(user.getUserAccount());

        // 1.2如果用户已存在，抛出错误
        if (selectByAccount != null) {
            throw new AuthorizationException(AuthorizationErrorCode.ACCOUNT_EXISTS);
        }
        try {

            baseMapper.insert(user);

        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException();
        }

        return user;
    }

    @Override
    public boolean importUser(XSSFWorkbook tpWorkbook) {
        // 1.获取excl的第一页
        Sheet sheet = tpWorkbook.getSheetAt(0);

        // 2.封装表格的模板
        UserExcel userVo = new UserExcel();
        userVo.setName("姓名");
        userVo.setUserAccount("帐号");
        userVo.setPhone("联系电话");
        userVo.setRole("角色(专家/系统管理员/企业管理员/企业用户/商务部门管理员/商务主管)");

        // 3.获取excl模板
        UserExclTemplate exclTemplate = new UserExclTemplate("用户模板", userVo);

        // 4.判断传来的文件是否与模板一致
        boolean same = ExclFile.isSpecifyTemplate(exclTemplate, sheet);


        // 5.不一致，抛出错误信息
        if (!same) {
            throw new AuthorizationException(AuthorizationErrorCode.DATA_NOT_SAME);
        }
        // 6、一致，导入数据
        int i = 1;
        User user = new User();
        try {
            while (true) {
                Row row = sheet.getRow(i++);
                // 6.1如果当前行没有数据了，直接退出循环
                if (row == null)
                    break;

                userVo = (UserExcel) ExclFile.createTemplateExcl(exclTemplate, row);
                // 6.2将对象的属性进行赋值
                BeanUtils.copyProperties(userVo, user);
                // 6.3保存用户
                insert(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException();
        }
//        importUserData(sheet);

        return true;
    }

    @Override
    public boolean updatePassword(String oldPassword, String newPassword, String againPassword, Integer userId) {

        User user = getById(userId);

        // 1.判断当前对象原来的密码是否一致
        if(!user.getDeCodePswd().equals(oldPassword)){
            throw new AuthorizationException(AuthorizationErrorCode.PSWD_ERROR);
        }

        // 2.判断两次输入的密码是否一致
        if(!newPassword.equals(againPassword)){
            return false;
        }

        // 3.修改密码
        User newUser = new User();
        newUser.setUserId(userId);
        newUser.setPassword(MD5Utils.recode(newPassword));

        try {
            updateById(newUser);
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException();
        }

        return true;
    }

    public void importUserData(Sheet sheet) {
        // 从第一行开始导入
        int i = 1;
        User user = new User();

        try {
            while (true) {
                Row row = sheet.getRow(i++);
                // 如果当前行没有数据了，直接退出循环
                if (row == null)
                    break;

//                ExclFile.createTemplateExcl();

                // 6.一致，将数据导入数据库
                // 6.1将对应的数据插入User实体类中
                Cell  name = row.getCell(0);
                Cell userAccount = row.getCell(1);
                Cell phone = row.getCell(2);
                Cell role = row.getCell(3);
                user.setUserAccount(userAccount.getStringCellValue());
                user.setName(name.getStringCellValue());
                user.setPhone(phone.getStringCellValue());
                user.setRole(User.getRoleType(role.getStringCellValue()));

                // 6.2保存用户
                insert(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new SysException();
        }
    }


    /**
     * 获取token
     *
     * @param userId
     * @param role
     * @return
     */
    private AuthenticationResultDTO makeAuthenticationResult(Integer userId, Integer role) {
        AuthenticationResultDTO result = new AuthenticationResultDTO();
        TokenResult tokenResult = tokenManager.generateToken(userId, role);
        result.setUserId(userId);
        result.setAccessToken(tokenResult.getAccessToken());
        result.setRole(role);

        return result;
    }
}
